package cn.ycxy.lbl.posts.controller;


import cn.ycxy.lbl.common.exception.BusinessException;
import cn.ycxy.lbl.common.exception.enums.ResponseEnum;
import cn.ycxy.lbl.common.restful.JsonPage;
import cn.ycxy.lbl.common.restful.R;
import cn.ycxy.lbl.member.service.IUserService;
import cn.ycxy.lbl.pojo.member.vo.UserDetailVO;
import cn.ycxy.lbl.pojo.posts.constant.DiscussPostsConstant;
import cn.ycxy.lbl.pojo.posts.domain.LblCsComment;
import cn.ycxy.lbl.pojo.posts.domain.LblCsDiscussPost;
import cn.ycxy.lbl.pojo.posts.dto.DiscussPostsAddDTO;
import cn.ycxy.lbl.pojo.posts.dto.DiscussPostsListDTO;
import cn.ycxy.lbl.pojo.posts.dto.DiscussPostsUpdateDTO;
import cn.ycxy.lbl.posts.service.ICommentService;
import cn.ycxy.lbl.posts.service.IDiscussPostsService;
import cn.ycxy.lbl.posts.service.ILikeService;
import cn.ycxy.lbl.posts.utils.SecurityContextUtils;
import cn.ycxy.lbl.posts.utils.SensitiveFilter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import io.swagger.annotations.*;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Api(tags = "帖子模块", value = "帖子模块")
@RestController
@RequestMapping("/discuss-posts")
public class DiscussPostsController implements DiscussPostsConstant {

    @Autowired
    private IDiscussPostsService discussPostsService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ICommentService commentService;
    @DubboReference
    private IUserService userService;
    @Autowired
    private ILikeService likeService;

    @Value("${qiniu.key.access}")
    private String accessKey;
    @Value("${qiniu.key.secret}")
    private String secretKey;
    @Value("${qiniu.bucket.post.name}")
    private String postBucketName;
    @Value("${qiniu.bucket.post.url}")
    private String postBucketUrl;
    @Autowired
    private SensitiveFilter sensitiveFilter;

    @ApiOperation("根据帖子id查询帖子详情")
    @GetMapping("/detail/{discussPostId}")
    public R<Map<String, Object>> getDiscussPost(@ApiParam(value = "帖子id", type = "int")
                                @PathVariable("discussPostId") Integer discussPostId){
        if (discussPostId == null){
            throw new BusinessException(ResponseEnum.BAD_REQUEST);
        }
        // 帖子
        LblCsDiscussPost discussPost = discussPostsService.getById(discussPostId);
        if (discussPost == null){
            throw new BusinessException(ResponseEnum.POSTS_NOT_FOUNT);
        }

        //作者
        UserDetailVO user = userService.getUserDetailById(discussPost.getUserId());
        // 评论: 给帖子的评论
        // 回复: 给评论的评论
        // 评论列表
        Page<LblCsComment> pageParam = new Page<>(1, Integer.MAX_VALUE);
        QueryWrapper<LblCsComment> wrapper = new QueryWrapper<>();
        wrapper.eq("entity_type", ENTITY_TYPE_POST)
                .eq("entity_id", discussPostId)
                .eq("serve_type", discussPost.getType())
                .orderByDesc("create_time");
        commentService.page(pageParam, wrapper);
        List<LblCsComment> commentList = pageParam.getRecords();

        //评论VO列表
        List<Map<String, Object>> commentVoList = new ArrayList<>();
        if (commentList != null){
            for (LblCsComment comment : commentList) {
                Map<String, Object> commentVo = new HashMap<>();
                //评论
                commentVo.put("commentVo", comment);
                //查询评论作者
                commentVo.put("user", userService.getUserDetailById(comment.getUserId()));
                QueryWrapper<LblCsComment> qw = new QueryWrapper<>();
                qw.eq("entity_type", ENTITY_TYPE_COMMENT)
                        .eq("entity_id", comment.getId())
                        .eq("serve_type", discussPost.getType())
                        .orderByDesc("create_time");
                //评论中的回复列表
                List<LblCsComment> replyList = commentService.list(qw);
                // 回复VO列表
                List<Map<String, Object>> replyVoList = new ArrayList<>();
                if (replyList != null){
                    for (LblCsComment reply : replyList) {
                        Map<String, Object> replyVo = new HashMap<>();
                        // 回复
                        replyVo.put("reply", reply);
                        // 作者
                        replyVo.put("user", userService.getUserDetailById(reply.getUserId()));
                        // 回复目标
                        UserDetailVO target = reply.getTargetId() == 0L ? null : userService.getUserDetailById(reply.getTargetId());
                        replyVo.put("target", target);
                        replyVoList.add(replyVo);
                    }
                }
                //评论中放入回复列表
                commentVo.put("replyList", replyVoList);
                //评论放入评论列表中
                commentVoList.add(commentVo);
            }
        }
        // 返回结果
        Map<String, Object> restMap = new HashMap<>();
        // 若是商品, 则查出浏览的人数和想要的人数
        if (discussPost.getType() == POSTS_DEAL_TYPE){
            restMap.put("postWatchCount", likeService.findEntityWatchCount(ENTITY_TYPE_POST, discussPostId));
            restMap.put("postWantCount", likeService.findEntityWantCount(ENTITY_TYPE_POST, discussPostId));
        }
        restMap.put("posts", discussPost);
        restMap.put("user", user);
        restMap.put("comments", commentVoList);
        return R.ok(restMap);
    }

    @GetMapping("/list")
    @ApiOperation("根据条件分页查询帖子")
    public R<JsonPage<Map<String,Object>>> listDiscussPosts(@Validated DiscussPostsListDTO discussPostsListDTO){
        //获取登录用户id
        Long userId = SecurityContextUtils.getUserId();
        Page<LblCsDiscussPost> pageParam = new Page<>(discussPostsListDTO.getPageNo(), discussPostsListDTO.getPageSize());
        QueryWrapper<LblCsDiscussPost> wrapper = new QueryWrapper<>();
        if (discussPostsListDTO.getIsMe() != null && discussPostsListDTO.getIsMe() == 1){
            //查询自己发布的帖子
            wrapper.eq("user_id", userId);
        }
        //这里要判断什么帖子类型(0失物招领, 1拼车, 2校园, 3二手交易)
        if (discussPostsListDTO.getType() == -1){
            // 首页失物招领/拼车全查
            //使用lambda表达式, 提升查询优先级(也就是相当于'(type=0 or type==1)',使两个条件变成组合条件)
            wrapper.and(o -> o.eq("type", 0).or().eq("type", 1));
        }else {
            wrapper.eq("type", discussPostsListDTO.getType());
            if (discussPostsListDTO.getType() == POSTS_DEAL_TYPE){
                wrapper.eq("is_finish_deal", 0);
            }
        }
        //若是查询交易帖子, 则必须携带classifyId
        if (discussPostsListDTO.getType() == POSTS_DEAL_TYPE && discussPostsListDTO.getClassifyId() == null){
            throw new BusinessException(ResponseEnum.BAD_REQUEST);
        }
        //是否要组装分类id查询, 并判断是否全查
        wrapper.and(discussPostsListDTO.getClassifyId() != null && discussPostsListDTO.getClassifyId() != 0,
                o -> o.eq("classify_id", discussPostsListDTO.getClassifyId())
        );
        if (discussPostsListDTO.getIsHot() != null && discussPostsListDTO.getIsHot() == 1){
            //根据点赞分数排名
            wrapper.orderByDesc("score");
        }
        wrapper.orderByDesc("create_time");
        discussPostsService.page(pageParam, wrapper);
        List<Map<String, Object>> mapList = new ArrayList<>(pageParam.getRecords().size());
        for (LblCsDiscussPost post : pageParam.getRecords()) {
            Map<String, Object> map = new HashMap<>();
            //作者
            UserDetailVO user = userService.getUserDetailById(post.getUserId());
            map.put("user", user);
            map.put("post", post);
            if (discussPostsListDTO.getType() == POSTS_SCENERY_TYPE){   //只有校园风景能点赞
                map.put("likeStatus", likeService.findEntityLikeStatus(userId, POSTS_SCENERY_TYPE, post.getId().intValue()));
                map.put("likeCount", likeService.findEntityLikeCount(POSTS_SCENERY_TYPE, post.getId().intValue()));
            }
            mapList.add(map);
        }
        JsonPage<Map<String, Object>> jsonPage = getJsonPage(discussPostsListDTO, pageParam.getTotal(), mapList);
        return R.ok(jsonPage);
    }

    @PostMapping("/add")
    @ApiOperation("新增帖子的方法")
    @PreAuthorize("hasRole('user')")
    public R<Void> addDiscussPosts(@Validated @RequestBody DiscussPostsAddDTO discussPostsAddDTO){
        //获取登录用户id
        Long userId = SecurityContextUtils.getUserId();
        LblCsDiscussPost discussPost = new LblCsDiscussPost();
        BeanUtils.copyProperties(discussPostsAddDTO, discussPost);
        discussPost.setUserId(userId.intValue());
        // 敏感词过滤
        discussPost.setContent(sensitiveFilter.filter(discussPostsAddDTO.getContent()));
        boolean save = discussPostsService.save(discussPost);
        if (!save){
            throw new BusinessException(ResponseEnum.POSTS_SAVE_ERROR);
        }
        if (discussPostsAddDTO.getType() != POSTS_SCENERY_TYPE){
            //使用rabbitmq异步发送消息, 把帖子添加到es中
            rabbitTemplate.convertAndSend(CS_POSTS_EX, CS_POSTS_ADD_RK, discussPost);
        }

        return R.ok();
    }

    @ApiOperation("删除帖子的方法")
    @PostMapping("/delete")
    @PreAuthorize("hasRole('user')")
    public R<Void> deleteDiscussPosts(@Validated @RequestBody DiscussPostsUpdateDTO discussPostsUpdateDTO){

        if (!discussPostsService.removeById(discussPostsUpdateDTO.getId())){
            throw new BusinessException(ResponseEnum.POSTS_DELETE_FAILED);
        }
        LblCsDiscussPost discussPost = new LblCsDiscussPost();
        discussPost.setId(discussPostsUpdateDTO.getId());
        discussPost.setType(discussPostsUpdateDTO.getPostsType());
        if (discussPostsUpdateDTO.getPostsType() != POSTS_SCENERY_TYPE){
            //使用rabbitmq异步发送消息, 把帖子从es中删除
            rabbitTemplate.convertAndSend(CS_POSTS_EX, CS_POSTS_DEL_RK, discussPost);
        }
        return R.ok();
    }

    @ApiOperation("获取七牛云图片上传token")
    @GetMapping("/uploadToken")
    public R<Map<String, String>> getUploadToken(){
        Auth auth = Auth.create(accessKey, secretKey);
        //设置一小时过期
        String uploadToken = auth.uploadToken(postBucketName);
        Map<String, String> restMap = new HashMap<>();
        restMap.put("uploadToken", uploadToken);
        restMap.put("lookImgPre", postBucketUrl);
        return R.ok(restMap);
    }

    @ApiOperation("获取用户发布的帖子")
    @GetMapping("/userPosts")
    public R<JsonPage<Map<String,Object>>> getUserPosts(@Validated DiscussPostsListDTO discussPostsListDTO){
        Long userId = SecurityContextUtils.getUserId();
        if (userId == 0){
            userId = 2L;
        }
        Page<LblCsDiscussPost> pageParam = new Page<>(discussPostsListDTO.getPageNo(), discussPostsListDTO.getPageSize());
        QueryWrapper<LblCsDiscussPost> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("type", discussPostsListDTO.getType());
        if (discussPostsListDTO.getIsFinishDeal() != null){
            wrapper.eq("is_finish_deal", discussPostsListDTO.getIsFinishDeal());
        }
        wrapper.orderByDesc("create_time");
        discussPostsService.page(pageParam, wrapper);
        List<Map<String, Object>> mapList = new ArrayList<>(pageParam.getRecords().size());
        for (LblCsDiscussPost post : pageParam.getRecords()) {
            Map<String, Object> map = new HashMap<>();
            //作者
            UserDetailVO user = userService.getUserDetailById(post.getUserId());
            map.put("user", user);
            map.put("post", post);
            if (discussPostsListDTO.getType() == POSTS_SCENERY_TYPE){   //只有校园风景能点赞
                map.put("likeStatus", likeService.findEntityLikeStatus(userId, POSTS_SCENERY_TYPE, post.getId().intValue()));
                map.put("likeCount", likeService.findEntityLikeCount(POSTS_SCENERY_TYPE, post.getId().intValue()));
            }
            mapList.add(map);
        }
        JsonPage<Map<String, Object>> jsonPage = getJsonPage(discussPostsListDTO, pageParam.getTotal(), mapList);
        return R.ok(jsonPage);
    }

    @ApiOperation("更新帖子状态")
    @PreAuthorize("hasRole('user')")
    @PostMapping("/deal/update")
    public R<Void> dealConfirm(@Validated @RequestBody DiscussPostsUpdateDTO discussPostsUpdateDTO){
        LblCsDiscussPost discussPost = new LblCsDiscussPost();
        BeanUtils.copyProperties(discussPostsUpdateDTO, discussPost);
        if (!discussPostsService.updateById(discussPost)) {
            throw new BusinessException(ResponseEnum.UPDATE_ERROR);
        }
        //完成交易, 移除搜索
        if (discussPostsUpdateDTO.getIsFinishDeal() != null && discussPostsUpdateDTO.getIsFinishDeal() == 1){
            discussPost.setType(POSTS_DEAL_TYPE);
            //使用rabbitmq异步发送消息, 把帖子从es中删除
            rabbitTemplate.convertAndSend(CS_POSTS_EX, CS_POSTS_DEL_RK, discussPost);
        }
        return R.ok();
    }


    private JsonPage<Map<String, Object>> getJsonPage(DiscussPostsListDTO discussPostsListDTO, Long total, List<Map<String, Object>> mapList) {
        JsonPage<Map<String, Object>> jsonPage = new JsonPage<>();
        jsonPage.setPage(discussPostsListDTO.getPageNo());
        jsonPage.setPageSize(discussPostsListDTO.getPageSize());
        jsonPage.setTotal(total);
        jsonPage.setList(mapList);
        return jsonPage;
    }
}
